#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct
{
	int deposit;
	int semid;
}Account;
typedef union
{
	int val;
	struct semid_ds* buf;
	unsigned short* array;
}my_semun;
int I(void);
void P(int semid);
void V(int semid);
void D(int semid);
void withdraw(Account* account,int amount);
int main(void)
{
	key_t k = 888;
	int shmid = shmget(k,sizeof(Account),IPC_CREAT | 0777);
	if(shmid == -1)
	{
		perror("shmget error");
		return 1;
	}
	// 映射
	Account* account = shmat(shmid,0,0);
	account->deposit = 888888;
	account->semid = I();
	V(account->semid);
	int pid = fork();
	if(pid == -1)
	{
		perror("fork error");
		// 解除映射
		shmdt(account);
		// 删除共享内存
		shmctl(shmid,IPC_RMID,NULL);
		// 删除信号量集
		D(account->semid);
		return 1;
	}
	else if(pid > 0)
	{
		withdraw(account,888888);
		wait(NULL);
		// 删除信号量集
		D(account->semid);
		// 解除映射
		shmdt(account);
		// 删除共享内存
		shmctl(shmid,IPC_RMID,NULL);
	}
	else if(pid == 0)
	{
		withdraw(account,888888);
		// 解除映射
		shmdt(account);
	}
	return 0;
}
void withdraw(Account* account,int amount)
{
	// 进行P操作，其他进程会阻塞
	P(account->semid);
	if(amount <= account->deposit)
	{
		account->deposit -= amount;
	}
	printf("process %d withdraw\n",(int)getpid());
	sleep(3);
	// 使其他进程继续运行
	V(account->semid);
}
int I(void)
{
	// 创建信号量集
	int semid = semget(IPC_PRIVATE,1,IPC_CREAT | 0777);
	if(semid != -1)
	{
		
		my_semun val;
		val.val = 0;
		// 初始化信号量集
		semctl(semid,0,SETALL,&val);
	}
	return semid;
}
void P(int semid)
{
	// 使用sembuf结构体进行P操作
	struct sembuf buf[1] = {{0,-1,SEM_UNDO}};
	semop(semid,buf,1);
}
void V(int semid)
{
	// 使用sembuf结构体进行V操作
	struct sembuf buf[1] = {{0,1,SEM_UNDO}};
	semop(semid,buf,1);
}
void D(int semid)
{
	// 删除信号量集
	semctl(semid,0,IPC_RMID,NULL);
}
